package com.hsqyz.esp32_led.netty.handler;

import com.hsqyz.esp32_led.factory.MessageProcessorFactory;
import com.hsqyz.esp32_led.model.dto.Esp32MessageDto;
import com.hsqyz.esp32_led.netty.cache.GlobalChannelCache;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 该类继承自ChannelInboundHandlerAdapter，作为Netty服务端的数据接收处理器。
 * 它实现了多个Netty的回调方法，用于处理客户端连接的各种生命周期事件和异常情况。
 * 注意：根据需求，可以删除未使用的重写方法以优化代码。
 */
@Slf4j
@Component
@ChannelHandler.Sharable
@RequiredArgsConstructor
public class Esp32SocketMsgInHandler extends ChannelInboundHandlerAdapter {

    private final MessageProcessorFactory messageProcessorFactory;

    private final GlobalChannelCache channelCache;


    /**
     * 当通道注册到其事件循环时调用。
     * 可在此处执行初始化操作，例如设置通道属性或订阅其他事件。
     *
     * @param ctx 通道上下文，用于与通道交互
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        String channelId = ctx.channel().id().asLongText();
        log.info("建立连接新的channel:{}", channelId);
    }

    /**
     * 当通道从其事件循环中取消注册时调用。
     * 可在此处执行清理操作，例如关闭通道或释放资源。
     *
     * @param ctx 通道上下文，用于与通道交互
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端断开链接【channelUnregistered】，{}", ctx.channel());
    }

    /**
     * 当通道变为可读时调用，表示可以开始读取数据。
     * 可在此处开启读取操作。
     *
     * @param ctx 通道上下文，用于与通道交互
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端连接成功【channelActive】，{}", ctx.channel());
    }

    /**
     * 当通道变为不可读时调用，可能是因为通道关闭或暂时无数据可读。
     * 可在此处停止读取操作或进行其他处理。
     *
     * @param ctx 通道上下文，用于与通道交互
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.error("客户端断开链接【channelInactive】，{}", ctx.channel());
        channelCache.removeChannel(ctx);
        ctx.close();
    }

    /**
     * 当通道接收到数据时调用。
     * 可在此处处理接收到的数据。
     *
     * @param ctx 通道上下文，用于与通道交互
     * @param msg 接收到的数据对象
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            // 转换成报文数据对象
            Esp32MessageDto messageDto = (Esp32MessageDto) msg;

            // 判断是否是注册命令，如果是则将ctx中的channel加入到缓存中。
            if ("register".equals(messageDto.getCmd())) {
                log.info("注册设备，clientId:{}", ctx.channel().id().asLongText());
                channelCache.addChannel(ctx.channel().id().asLongText(), ctx);
            }else {
                // 将消息丢进消息工厂进行处理
                this.messageProcessorFactory.acceptMessage(messageDto);
            }
        } catch (Exception e) {
            log.error("处理报文数据失败：{}", e.getMessage());
        }
    }

    /**
     * 当通道读取操作完成时调用，表示没有更多数据需要读取。
     * 可在此处进行清理或后续操作。
     *
     * @param ctx 通道上下文，用于与通道交互
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        log.info("channelReadComplete");
    }

    /**
     * 当用户事件触发时调用，例如自定义的通道事件。
     * 可在此处处理特定的用户事件。
     *
     * @param ctx 通道上下文，用于与通道交互
     * @param evt 用户触发的事件对象
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        log.info("userEventTriggered");
    }

    /**
     * 当通道的写入能力发生变化时调用，例如通道现在可以接受更多的写入操作。
     * 可在此处调整写入策略。
     *
     * @param ctx 通道上下文，用于与通道交互
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        log.info("channelWritabilityChanged");
    }

    /**
     * 当在通道处理链中抛出异常时调用。
     * 可在此处记录异常并决定是否关闭通道。
     *
     * @param ctx   通道上下文，用于与通道交互
     * @param cause 异常原因
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("exceptionCaught", cause);
    }

}
